# -*- coding: utf-8 -*-

import os
 
import wx
import wx.wizard as wizard
import wx.aui as aui
import wx.lib.buttonpanel as bp

import pystore.core.framework.job as job
import pystore.core.i18n as i18n
import pystore.core.framework.logger as logger
import images

def runInUi(f):
    """
      redirector function
      args:
        f:function/methon
      return ui safe , wrap method 
    """
    def resultFunction(*args,**keywordArgs):
        if wx.Thread_IsMain():
            return f(*args,**keywordArgs)
        
        wx.MutexGuiEnter();
        result=f(*args,**keywordArgs)
        wx.MutexGuiLeave();
        return result
    return resultFunction
    
class BaseView(object):
    """
    一个view如下图:
    ------------
    toolbar
    ------------
    contentPane
    
    
    ------------
     由toolbar和内容面板组成
    toolbar只安装本view相关的menu
    """
    def __init__(self,parentWindow):
        self.__window=wx.Panel(parentWindow)
        sizer =wx.BoxSizer(wx.VERTICAL)
        #sizer.Add(self.createToolbar(self.__window), 0, wx.EXPAND)
        sizer.Add(self.createContentPane(self.__window), 1, wx.EXPAND)
        self.__window.SetSizer(sizer)

    def createToolbar(self,parent):
        """
         还没想好toolbar应该是啥结构
         
        templet method ，需要子类override
        """
        result = wx.ToolBar(parent)
        result.AddControl(wx.StaticText(result, -1, "name"))
        return  result
    

    def createContentPane(self,parent):
        """
        createContentPane(wx.Window parent) -> wx.Window

         建立view主面板
        templet method ，需要子类override
        """
        raise NotImplementedError
    
    def getWindow(self):
        """
        getWindow() -> wx.Window 
          
         返回此view代表的窗口组件  
        """
        return self.__window
    
class BaseDialog(wx.Dialog):
    def __init__(self, parent,message=''):
        """提供一个标题栏的BaseDialog"""
        #SetExtraStyle的流程就是这样:
        pre = wx.PreDialog()
        pre.SetExtraStyle(wx.WS_EX_VALIDATE_RECURSIVELY)
        pre.Create(parent,size=(650,500),style=wx.RESIZE_BORDER|wx.DEFAULT_DIALOG_STYLE)
        self.PostCreate(pre)
        
        self.message=message

        buttons = wx.StdDialogButtonSizer() #wx.BoxSizer(wx.HORIZONTAL)
        ok = wx.Button(self, wx.ID_OK, _t("OK"))
        ok.SetDefault()
        buttons.AddButton(ok)
        buttons.AddButton(wx.Button(self, wx.ID_CANCEL, _t("Cancel")))
        buttons.Realize()
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.__createTitlePane(self), 0, wx.EXPAND)
        sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(self.createContentPane(self), 1, wx.EXPAND)
        sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.ALL, 5)
        sizer.Add(buttons,0,wx.ALIGN_RIGHT)
        
        #惯用法
        self.SetSizer(sizer)
        self.Layout()
        
    def __createTitlePane(self,parent):
        result=wx.Panel(parent)
        #result.SetBackgroundColour('white')
        sizer = wx.BoxSizer(wx.VERTICAL)
        result.SetSizer(sizer)

        self.__text_message = wx.StaticText(result)
        self.__text_message.SetLabel(self.message)
        self.__text_message.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
        
        sizer.Add(self.__text_message, 0, wx.EXPAND)
        return result
    
    def clearError(self):
        """
         清除错误消息，并还原构造器传入的原始消息
        """
        self.__text_message.SetLabel(self.message)
        self.__text_message.SetForegroundColour('black')
        
    def setError(self,text):
        '''
        setErrorMessage(self,str text)
        
         显示红色错误消息
        '''
        self.__text_message.SetLabel(text)
        self.__text_message.SetForegroundColour('red')
        
    def createContentPane(self,parent):
        '''
        createContentPane(wx.Window parent) -> wx.Window
        
         模板方法创建主内容面板,返回的主内容面板将被嵌入到标题栏下,按钮上
         子类需overide
        '''
        #默认实现一个提示性的Panel
        result=wx.Panel(parent)
        result.SetBackgroundColour('red')
        wx.StaticText(result, -1, 'need override createContentPane() ')
        return result


def getScreenCenterPosition(window):
    """
    getScreenCenterPosition(wx.Window window) -> tuple
    
    返回屏幕中心坐标 , 例如: (400,300)
    """
    width = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X ,window)
    height = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y ,window)
    return ((width-window.GetSize()[0])/2,(height-window.GetSize()[1])/2)
        

def runProgressDialog(parentWindow,title,func):
    '''
    runProgressDialog(basestring title,function func)
    
    args:
      func: func(IMonitor monitor)
      
    '''
    monitor = _DialogProgressMonitor(title)
    job.runJob(func,monitor)
    
    max = 1000
    dlg = wx.ProgressDialog(         title,
                               '',
                               maximum = max ,
                               parent=parentWindow,
                               style = wx.PD_SMOOTH 
                                |wx.PD_CAN_ABORT
                                |wx.PD_APP_MODAL
                                #| wx.PD_ELAPSED_TIME
                                #| wx.PD_ESTIMATED_TIME
                                #| wx.PD_REMAINING_TIME
                                )
    dlg.SetSize((600,400))
    
    keepGoing = True
    while keepGoing:
        import time
        wx.MilliSleep(100)
        if not monitor.isBegun:
            print 'not begin'
            dlg.Update(0,monitor.taskName)#很重要的update,因为如果不经常update, dialog就像卡死了一样搞不清状况
            continue
        
        if monitor.isDone:
            dlg.Update(max,monitor.taskName)
            keepGoing = False
            
        if not monitor.isDone :
            #print 'update:', value , ' monitor.sumWorked:' ,monitor.sumWorked ,' isCanceled:',monitor.isCanceled()
            value = int(monitor.sumWorked / monitor.totalWork * max)
            (keepGoing, skip) = dlg.Update(value,monitor.taskName)
            if not keepGoing : 
                monitor.setCanceled(True)
        
    dlg.Destroy()

class _DialogProgressMonitor(job.IMonitor):
    def __init__(self,title):
        self.title=title
        self.totalWork = 0
        self.sumWorked = 0.0
        self.taskName = ""
        self.isBegun =False
        self.isDone  =False
        self.canceled = False
        
    #override IMonitor
    def beginTask( self,name, totalWork):
        '''
        beginTask(basestring name,int totalWork)
        '''
        self.isBegun = True
        self.totalWork=totalWork
        
    #override IMonitor
    def setTaskName(self,name):
        '''
        setTaskName(basestring name)
        '''
        self.taskName = name

    #override IMonitor
    def isCanceled(self):
        '''
        isCanceled() -> bool
        '''
        return self.canceled
    
    def setCanceled(self,canceled):
        self.canceled = canceled
    
    #override IMonitor
    def worked(self,work):
        '''
        worked()
        '''
        self.internalWorked(work)

    def internalWorked(self,work):
        #print '_DialogProgressMonitor:work:',work,'sumWorked:',self.sumWorked,'totalWork:',self.totalWork,'isDone:',self.isDone
        self.sumWorked += work;
        if (self.sumWorked > self.totalWork) :
            self.sumWorked = self.totalWork;
        
        if (self.sumWorked < 0) :
            self.sumWorked = 0;

    #override IMonitor
    def done(self):
        '''
        done()
        '''
        self.isDone = True
        
class BaseValidator(wx.PyValidator):
    def __init__(self,errorHandler):
        '''
        __init__(self,IErrorHandler errorHandler)
        '''
        self.errorHandler=errorHandler
        self.oldColour=None
        
        wx.PyValidator.__init__(self)
        
        
    def setError(self,window,message,colour='pink'):
        '''
        setError(wx.Window window,basestring message,wx.Colour/str colour='pink')
        
         Validator对应的控件检查出问题后,设置错误消息并把控件颜色改变
        '''
        self.__setColour(window,colour) 
        self.errorHandler.setError(message)
        
    def clearError(self,window):
        '''
        setError(wx.Window window)
        
         验证ok后通常会解除原先设置的错误消息和颜色
        '''
        self.__restoreColour(window)
        self.errorHandler.clearError()
        
    def TransferToWindow(self):
        return True  

    def TransferFromWindow(self):
        return True  
    
    def __setColour(self,window,colour='pink'):
        if self.oldColour is None:
            self.oldColour = window.GetBackgroundColour()
        window.SetBackgroundColour(colour)
        window.SetFocus()
        window.Refresh()
        
    def __restoreColour(self,window):
        if self.oldColour is not None:
            window.SetBackgroundColour(self.oldColour)
            window.Refresh()
    

class IErrorHandler(object):
    '''
    示意接口,并不实现
    用在Wizard或Dialog上，用来显示错误消息
    '''
    def clearError(self):
        """
         清除错误消息
        """
    def setError(self,text):
        '''
        setError(self,basestring text)
         提示错误
        '''

class _PerstectiveButtonsView(BaseView):
    def __init__(self,parentWindow):
        BaseView.__init__(self,parentWindow)
        
    #override
    def createContentPane(self,parent):
        self.abc= 1
        self._buttonPanel = bp.ButtonPanel(self.getWindow(), -1,"",style=bp.BP_USE_GRADIENT|bp.BP_GRADIENT_HORIZONTAL,alignment = bp.BP_ALIGN_LEFT, )
        
        #Set ui properties
        bpArt = self._buttonPanel.GetBPArt()
        bpArt.SetGradientType(bp.BP_GRADIENT_VERTICAL)
        bpArt.SetMetric(bp.BP_BORDER_SIZE,0)
        bpArt.SetColor(bp.BP_TEXT_COLOR, wx.WHITE)
        bpArt.SetColor(bp.BP_BUTTONTEXT_COLOR, wx.WHITE)
        
        bpArt.SetColor(bp.BP_BORDER_COLOR, wx.Colour(00,00,00))
        bpArt.SetColor(bp.BP_GRADIENT_COLOR_FROM, wx.Colour(60,11,112))
        bpArt.SetColor(bp.BP_GRADIENT_COLOR_TO, wx.Colour(120,23,224))
          
        bpArt.SetColor(bp.BP_BUTTONTEXT_COLOR, wx.Colour(70,143,255))
        bpArt.SetColor(bp.BP_SEPARATOR_COLOR,  bp.BrightenColour(wx.Colour(60, 11, 112), 0.85))
        bpArt.SetColor(bp.BP_SELECTION_BRUSH_COLOR, wx.Color(225, 225, 255))
        bpArt.SetColor(bp.BP_SELECTION_PEN_COLOR, wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION))
        
        self._buttonPanel.DoLayout()
 

        return self._buttonPanel
    
    def addButton(self,perstectiveInfo):
        btn = bp.ButtonInfo(self._buttonPanel, id=wx.NewId(),
                                bmp=perstectiveInfo.bmp, 
                                text=perstectiveInfo.text,
                                kind=wx.ITEM_CHECK
                                )
        self._buttonPanel.AddButton(btn)

class Workbench(wx.Frame):
    def __init__(self):
        self.size = (600, 600)
        wx.Frame.__init__(self,None, -1, "pystore", size=self.size,#pos=pos,
                  style = wx.DEFAULT_FRAME_STYLE #|wx.MAXIMIZE 
                  )
        self.Centre()
        
        self._perstectiveInfos = {}
        self._views = {}
        self.addView(_VIEW_ID_PERSTECTIVE_BUTTONS,_PerstectiveButtonsView(self))
        
        self._isSetupFrameManager = False
        
        self._mgr = wx.aui.FrameManager()
        self._mgr.SetManagedWindow(self)

    def addView(self,viewId,view):
        self._views[viewId] = view

    def addPerstectiveInfo(self,perstectiveId,perstectiveInfo):
        self._perstectiveInfos[perstectiveId] =  perstectiveInfo
        self._views[_VIEW_ID_PERSTECTIVE_BUTTONS].addButton(perstectiveInfo)
        
        
    def activatePerstective(self,perstectiveId):
        if not self._isSetupFrameManager :
            for perstectiveId ,perstectiveInfo in self._perstectiveInfos.items() : 
                for viewId in perstectiveInfo.getViewKeys():
                    self._mgr.AddPane(self._views[viewId].getWindow(),perstectiveInfo.getViewPaneInfo(viewId))
                
        self._mgr.Update()
        self._isSetupFrameManager = True
    
    def _hideAllPane(self):
        all_panes = self._mgr.GetAllPanes()
        for paneInfo in self._mgr.GetAllPanes():
            if not paneInfo.IsToolbar():
                paneInfo.Hide()
        
    def _addPerstectiveButton(self,text,bmp):
        btn = bp.ButtonInfo(self._perstectiveButtonPanel, wx.NewId(),
                            text=text,
                            bmp=bmp, 
                            kind=wx.ITEM_CHECK)
        self._perstectiveButtonPanel.AddButton(btn)
    

class PerstectiveInfo(object):
    def __init__(self,text,bmp):
        self.bmp = bmp
        self.text = text
        self._viewPaneInfos = {}
        self._viewPaneInfosIndex = []
        self.addViewPaneInfo(_VIEW_ID_PERSTECTIVE_BUTTONS,aui.PaneInfo().Caption(_("")).Top()\
             .CloseButton(False).Floatable(False).CaptionVisible(False).Layer(1).MinSize((64,64)).Fixed())
        
    def addViewPaneInfo(self,viewId,paneInfo):
        '''addView(self,str viewId, aui.PaneInfo paneInfo)'''
        self._viewPaneInfos[viewId] = paneInfo.Name(viewId)
        self._viewPaneInfosIndex.append(viewId)
        
    def getViewKeys(self):
        return self._viewPaneInfosIndex[:]
    
    def getViewPaneInfo(self,viewId):
        return self._viewPaneInfos[viewId]

_log=logger.getLog('ui') 
_t=i18n.t_

_VIEW_ID_PERSTECTIVE_BUTTONS = 'view.perstectiveButtons'